﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using System.IO;
using System.Text;
using Newtonsoft.Json;
using HigLabo.Net.Extensions;

namespace HigLabo.Net.BoxNet
{
    /// <summary>
    /// 
    /// </summary>
    public partial class BoxClient 
    {
        public override OAuth2AccessToken GetAccessToken(String code)
        {
            var cl = new HttpClient();
            cl.ResponseEncoding = Encoding.UTF8;
            var cm = this.CreateGetAccessTokenCommand(code);
            var text = cl.GetBodyText(cm);
            var t = OAuth2AccessToken.Create(this.ClientID, text);
            return t;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        private String GetResponseBodyText(BoxCommand command)
        {
            var cm = this.CreateHttpRequestCommand(command.MethodName, command.GetBaseUrl(), command.GetParameters());
            if (command.MethodName == HttpMethodName.Post
             || command.MethodName == HttpMethodName.Put
             || command.MethodName == HttpMethodName.Move
             || command.MethodName == HttpMethodName.Copy)
            {
                cm.SetBodyStream(command.Data);
            }
            var res = this.GetResponse(cm);
            if (res.StatusCode != HttpStatusCode.OK)
            {
                throw new BoxResponseException(res);
            }
            return res.BodyText;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        private Stream GetHttpWebResponse(BoxCommand command)
        {
            var cm = this.CreateHttpRequestCommand(command.MethodName, command.GetBaseUrl(), command.GetParameters());
            if (command.MethodName == HttpMethodName.Post
             || command.MethodName == HttpMethodName.Put
             || command.MethodName == HttpMethodName.Move
             || command.MethodName == HttpMethodName.Copy)
            {
                cm.SetBodyStream(command.Data);
            }
            var res = this.GetHttpWebResponse(cm);
            return res.GetResponseStream();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        private String Post(UploadNewVersionFileCommand command)
        {
            var d = command.GetParameters();
            var cm = this.CreateHttpRequestCommand(command.MethodName, command.GetBaseUrl(BoxApiUrlType.Upload), d);
            String boundary = UploadFileCommand.GetBoundaryString();
            cm.ContentType = "multipart/form-data; boundary=\"" + boundary + "\"";
            cm.SetBodyStream(command.CreatePostData(boundary));

            return this.GetBodyText(cm);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        private String Post(UploadFileCommand command)
        {
            var d = command.GetParameters();
            var cm = this.CreateHttpRequestCommand(command.MethodName, command.GetBaseUrl(BoxApiUrlType.Upload), d);
            String boundary = UploadFileCommand.GetBoundaryString();
            cm.ContentType = "multipart/form-data; boundary=\"" + boundary + "\"";
            cm.SetBodyStream(command.CreatePostData(boundary));

            return this.GetBodyText(cm);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public Folder CreateFolder(CreateFolderCommand command)
        {
            String text = this.GetResponseBodyText(command);
            return new Folder(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="folderID"></param>
        /// <param name="folderName"></param>
        /// <returns></returns>
        public Folder CreateFolder(String folderID, String folderName)
        {
            var cm = new CreateFolderCommand();
            cm.FolderID = folderID;
            cm.NewFolderName = folderName;
            return this.CreateFolder(cm);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public Folder GetFolderInfo(GetFolderInfoCommand command)
        {
            String text = this.GetResponseBodyText(command);
            return new Folder(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="folderID"></param>
        /// <returns></returns>
        public Folder GetFolderInfo(String folderID)
        {
            var cm = new GetFolderInfoCommand();
            cm.FolderID = folderID;
            return this.GetFolderInfo(cm);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public ItemCollection RetrieveFolderItems(RetrieveFolderItemsCommand command)
        {
            String text = this.GetResponseBodyText(command);
            return new ItemCollection(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="folderID"></param>
        /// <returns></returns>
        public ItemCollection RetrieveFolderItems(String folderID)
        {
            var cm = new RetrieveFolderItemsCommand();
            cm.FolderID = folderID;
            return this.RetrieveFolderItems(cm);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public Folder UpdateFolderInfo(UpdateFolderInfoCommand command)
        {
            String text = this.GetResponseBodyText(command);
            return new Folder(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="folderID"></param>
        /// <param name="folderName"></param>
        /// <returns></returns>
        public Folder UpdateFolderInfo(String folderID, String folderName)
        {
            var cm = new UpdateFolderInfoCommand();
            cm.FolderID = folderID;
            cm.NewName = folderName;
            return this.UpdateFolderInfo(cm);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public File GetFileInfo(GetFileInfoCommand command)
        {
            String text = this.GetResponseBodyText(command);
            return new File(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public File UpdateFileInfo(UpdateFileInfoCommand command)
        {
            String text = this.GetResponseBodyText(command);
            return new File(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public File CopyFile(CopyFileCommand command)
        {
            if (String.IsNullOrEmpty(command.DestinationFolderID)) throw new ArgumentNullException("CopyFileCommand.DestinationFolderID");
            String text = this.GetResponseBodyText(command);
            return new File(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="fileID"></param>
        /// <param name="destinationFolderID"></param>
        /// <returns></returns>
        public File CopyFile(String fileID, String destinationFolderID)
        {
            var cm = new CopyFileCommand();
            cm.FileID = fileID;
            cm.DestinationFolderID = destinationFolderID;
            return this.CopyFile(cm);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        public String DeleteFile(DeleteFileCommand command)
        {
           return this.GetResponseBodyText(command);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="fileID"></param>
        /// <param name="version"></param>
        /// <returns></returns>
        public String DeleteFile(String fileID, String version)
        {
            var cm = new DeleteFileCommand();
            cm.FileID = fileID;
            cm.Version = version;
            return this.DeleteFile(cm);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public Byte[] DownloadFile(DownloadFileCommand command)
        {
            var rep = this.GetHttpWebResponse(command);
            return rep.ToByteArray();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="fileID"></param>
        /// <param name="version"></param>
        /// <returns></returns>
        public Byte[] DownloadFile(String fileID, String version)
        {
            var cm = new DownloadFileCommand();
            cm.FileID = fileID;
            cm.Version = version;
            return this.DownloadFile(cm);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public CommentCollection GetCommentsOnFile(GetCommentsOnFileCommand command)
        {
            String text = this.GetResponseBodyText(command);
            return new CommentCollection(text);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public TemporaryFile UploadNewVersion(UploadNewVersionFileCommand command)
        {
            String text = Post(command);
            return new TemporaryFile(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public Comment AddCommentToFile(AddCommentCommand command)
        {
            command.AddType = CommentType.Comment;
            String text = this.GetResponseBodyText(command);
            return new Comment(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public Comment AddCommentToDiscussion(AddCommentCommand command)
        {
            command.AddType = CommentType.Discussion;
            String text = this.GetResponseBodyText(command);
            return new Comment(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public Comment ChangeCommentMessage(ChangeCommentCommand command)
        {
            String text = this.GetResponseBodyText(command);
            return new Comment(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public Comment GetCommentInfo(GetCommentCommand command)
        {
            String text = this.GetResponseBodyText(command);
            return new Comment(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        public String DeleteComment(DeleteCommentCommand command)
        {
            return this.GetResponseBodyText(command);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public Discussion CreateDiscussion(CreatediscussionCommand command)
        {
            String text = this.GetResponseBodyText(command);
            return new Discussion(text);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public CommentCollection RetrieveDiscussionComments(RetrieveDiscussionCommentsCommand command)
        {
            String text = this.GetResponseBodyText(command);
            return new CommentCollection(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public Discussion UpdateDiscussion(UpdateDiscussionCommand command)
        {
            String text = this.GetResponseBodyText(command);
            return new Discussion(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public EventCollection GetEvents(GetEventsCommand command)
        {
            String text = this.GetResponseBodyText(command);
            return new EventCollection(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public TemporaryFile UploadFile(UploadFileCommand command)
        {
            String text = Post(command);
            return new TemporaryFile(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public String GetFileVersions(GetFileVersionsCommand command)
        {
            return this.GetResponseBodyText(command);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="fileID"></param>
        /// <returns></returns>
        public String GetFileVersions(String fileID)
        {
            var cm = new GetFileVersionsCommand();
            cm.FileID = fileID;
            return this.GetFileVersions(cm);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public Folder GetRootFolder()
        {
            return this.GetFolderInfo("0");
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public ItemCollection GetRootItems()
        {
            return this.RetrieveFolderItems("0");
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public List<Folder> GetRootFolders()
        {
            var items = this.RetrieveFolderItems("0");
            return this.GetFolders(items);
        }
    }
}
